﻿// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证（版本 2.0）进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动！任何基于本项目二次开发而产生的一切法律纠纷和责任，我们不承担任何责任！

using Admin.NET.Application.Entity;
using Admin.NET.Core;
using Furion.FriendlyException;
using SqlSugar;
using System.ComponentModel;

namespace Admin.NET.Application.Service.PlanStatus;

/// <summary>
/// 计划状态服务 🧩
/// </summary>
[ApiDescriptionSettings(ApplicationConst.GroupName, Order = 100)]
public partial class PlanStatusService : IDynamicApiController, ITransient
{
    private readonly SqlSugarRepository<PlanList> _planListRep;
    private readonly SqlSugarRepository<PlanType> _planTypeRep;
    private readonly ISqlSugarClient _sqlSugarClient;

    public PlanStatusService(SqlSugarRepository<PlanList> planListRep, SqlSugarRepository<PlanType> planTypeRep, ISqlSugarClient sqlSugarClient)
    {
        _planListRep = planListRep;
        _planTypeRep = planTypeRep;
        _sqlSugarClient = sqlSugarClient;
    }

    /// <summary>
    /// 分页查询计划状态 🔖
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [DisplayName("分页查询计划状态")]
    [ApiDescriptionSettings(Name = "Page"), HttpPost]
    public async Task<SqlSugarPagedList<PlanStatusListOutput>> Page(PagePlanStatusListInput input)
    {
        input.Keyword = input.Keyword?.Trim();
        input.Ch = input.Ch?.Trim();
        input.Fd = input.Fd?.Trim();
        input.workTime = input.workTime?.Trim();

        // 获取所有计划分类（去除租户/机构/数据权限过滤，所有用户可见）
        var planTypes = await _planTypeRep.AsQueryable()
            .OrderBy(x => x.OrderNo)
            .ToListAsync();
        if (planTypes == null || !planTypes.Any()) throw Oops.Oh("获取计划分类失败");

        // 基础查询：只应用『关键字/船号/分段/月份』，用于承载后续融合
        var baseQuery = _planListRep.AsQueryable()
            .WhereIF(!string.IsNullOrWhiteSpace(input.Keyword), u => u.Ch.Contains(input.Keyword) || u.Fd.Contains(input.Keyword))
            .WhereIF(!string.IsNullOrWhiteSpace(input.Ch), u => u.Ch.Contains(input.Ch))
            .WhereIF(!string.IsNullOrWhiteSpace(input.Fd), u => u.Fd.Contains(input.Fd));

        if (!string.IsNullOrWhiteSpace(input.workTime))
        {
            var (startDate, endDate) = DateTimeUtil.CalculateWorkTimeRange(input.workTime);
            baseQuery = baseQuery.Where(u =>
                (u.PlanStart >= startDate && u.PlanStart <= endDate) ||
                (u.PlanEnd >= startDate && u.PlanEnd <= endDate)
            );
        }

        // 先在『PlanList 维度』做区域/分类等筛选，得到要展示的 (Ch,Fd) 集合
        var selectorQuery = baseQuery
            .WhereIF(input.WorkAreaId.HasValue, u => u.WorkAreaId == input.WorkAreaId)
            .WhereIF(input.ClassName.HasValue, u => u.ClassName == input.ClassName);

        var selectorList = await selectorQuery.ClearFilter<IOrgIdFilter>().ToListAsync();
        var selectedKeys = selectorList
            .GroupBy(x => new { x.Ch, x.Fd })
            .Select(g => new { g.Key.Ch, g.Key.Fd })
            .ToList();

        // 如果没有命中任何分段，直接返回空分页
        if (selectedKeys.Count == 0)
        {
            return new SqlSugarPagedList<PlanStatusListOutput>
            {
                Items = new List<PlanStatusListOutput>(),
                Total = 0,
                Page = input.Page,
                PageSize = input.PageSize
            };
        }

        // 再用『基础查询（不再受区域/分类过滤）』在选中的 (Ch,Fd) 上汇总融合所有分类数据
        var baseList = await baseQuery.ClearFilter<IOrgIdFilter>().ToListAsync();
        var keySet = new HashSet<string>(selectedKeys.Select(k => $"{k.Ch}||{k.Fd}"));
        var allPlanLists = baseList.Where(x => keySet.Contains($"{x.Ch}||{x.Fd}")).ToList();

        // 按船号和分段号分组处理
        var groupedResults = await ProcessPlanGroups(allPlanLists, planTypes);

        // 应用状态筛选
        if (input.Status.HasValue)
        {
            var isFinished = input.Status == FinishStatusEnum.Finish;
            groupedResults = groupedResults.Where(x => x.IsAllFinished == isFinished).ToList();
        }

        // 手动分页处理
        var totalCount = groupedResults.Count;
        var items = groupedResults
            .OrderBy(x => x.Ch)
            .ThenBy(x => x.Fd)
            .Skip((input.Page - 1) * input.PageSize)
            .Take(input.PageSize)
            .ToList();

        return new SqlSugarPagedList<PlanStatusListOutput>
        {
            Items = items,
            Total = totalCount,
            Page = input.Page,
            PageSize = input.PageSize
        };
    }

    /// <summary>
    /// 处理计划分组数据
    /// </summary>
    /// <param name="planLists">计划列表</param>
    /// <param name="planTypes">计划类型列表</param>
    /// <returns>处理后的分组结果</returns>
    private async Task<List<PlanStatusListOutput>> ProcessPlanGroups(List<PlanList> planLists, List<PlanType> planTypes)
    {
        var results = new List<PlanStatusListOutput>();

        // 按船号和分段号分组
        var grouped = planLists.GroupBy(x => new { x.Ch, x.Fd }).ToList();

        foreach (var group in grouped)
        {
            var row = new PlanStatusListOutput
            {
                Ch = group.Key.Ch,
                Fd = group.Key.Fd,
                Categories = new List<PlanReportCategoryDto>()
            };

            // 为每个计划类型创建分类项
            foreach (var type in planTypes)
            {
                var plan = group.FirstOrDefault(x => x.ClassName == type.Id);

                // 计算开工延期天数
                // planStart 是计划开工，actualStart 是实际开工
                int startDelayDays = 0;
                if (plan != null && plan.ActualStart.HasValue && plan.PlanStart.HasValue)
                {
                    // 只计算日期部分的差值（不包含时间）
                    var planStartDate = plan.PlanStart.Value.Date;      // 计划开工
                    var actualStartDate = plan.ActualStart.Value.Date;  // 实际开工
                    var daysDiff = (actualStartDate - planStartDate).Days;
                    // 如果实际开工时间晚于计划开工时间，记录延期天数
                    if (daysDiff > 0)
                    {
                        startDelayDays = daysDiff;
                    }
                }

                // 计算完工延期天数
                // planEnd 是计划完工，actualEnd 是实际完工
                int endDelayDays = 0;
                if (plan != null && plan.ActualEnd.HasValue && plan.PlanEnd.HasValue)
                {
                    // 只计算日期部分的差值（不包含时间）
                    var planEndDate = plan.PlanEnd.Value.Date;      // 计划完工
                    var actualEndDate = plan.ActualEnd.Value.Date;  // 实际完工
                    var daysDiff = (actualEndDate - planEndDate).Days;
                    // 如果实际完工时间晚于计划完工时间，记录延期天数
                    if (daysDiff > 0)
                    {
                        endDelayDays = daysDiff;
                    }
                }

                // 计算周期（天）
                int? plannedCycleDays = null;
                if (plan?.PlanStart.HasValue == true && plan?.PlanEnd.HasValue == true)
                {
                    plannedCycleDays = (plan.PlanEnd.Value.Date - plan.PlanStart.Value.Date).Days;
                }

                int? actualCycleDays = null;
                if (plan?.ActualStart.HasValue == true && plan?.ActualEnd.HasValue == true)
                {
                    actualCycleDays = (plan.ActualEnd.Value.Date - plan.ActualStart.Value.Date).Days;
                }

                row.Categories.Add(new PlanReportCategoryDto
                {
                    ClassName = type.Id,
                    ClassNameFkDisplayName = type.Name,
                    PlanStart = plan?.PlanStart,
                    PlanEnd = plan?.PlanEnd,
                    ActualStart = plan?.ActualStart,
                    ActualEnd = plan?.ActualEnd,
                    StartDelayDays = startDelayDays,
                    EndDelayDays = endDelayDays,
                    PlannedCycleDays = plannedCycleDays,
                    ActualCycleDays = actualCycleDays
                });
            }

            // 判断是否全部完成：最后一个分类项有实际完工日期即可
            //var lastCategory = row.Categories.LastOrDefault();
            var lastCategory = row.Categories.Find(x => x.ClassNameFkDisplayName == "分段报验");
            row.IsAllFinished = lastCategory != null && lastCategory.ActualEnd.HasValue;

            results.Add(row);
        }

        return results;
    }

    /// <summary>
    /// 获取计划状态详情 ℹ️
    /// </summary>
    /// <param name="ch">船号</param>
    /// <param name="fd">分段号</param>
    /// <returns></returns>
    [DisplayName("获取计划状态详情")]
    [ApiDescriptionSettings(Name = "Detail"), HttpGet]
    public async Task<PlanStatusListOutput> Detail([FromQuery] string ch, [FromQuery] string fd)
    {
        if (string.IsNullOrWhiteSpace(ch) || string.IsNullOrWhiteSpace(fd))
            throw Oops.Oh("船号和分段号不能为空");

        // 获取所有计划分类
        var planTypes = await _planListRep.Context.Queryable<PlanType>().ToListAsync();
        if (planTypes == null || !planTypes.Any()) throw Oops.Oh("获取计划分类失败");

        // 获取指定船号分段号的计划列表
        var planLists = await _planListRep.GetListAsync(u => u.Ch == ch && u.Fd == fd);
        
        if (!planLists.Any())
            throw Oops.Oh("未找到指定的计划数据");

        // 处理分组数据
        var groupedResults = await ProcessPlanGroups(planLists, planTypes);
        return groupedResults.FirstOrDefault();
    }

    /// <summary>
    /// 获取计划状态统计 📊
    /// </summary>
    /// <param name="workTime">作业时间（格式：yyyy-MM）</param>
    /// <returns></returns>
    [DisplayName("获取计划状态统计")]
    [ApiDescriptionSettings(Name = "Statistics"), HttpPost]
    public async Task<object> GetStatistics([FromBody] string workTime = null)
    {
        // 获取所有计划分类
        var planTypes = await _planListRep.Context.Queryable<PlanType>().ToListAsync();
        if (planTypes == null || !planTypes.Any()) throw Oops.Oh("获取计划分类失败");

        // 构建查询
        var query = _planListRep.AsQueryable();

        // 如果指定了月份，添加时间范围筛选
        if (!string.IsNullOrWhiteSpace(workTime))
        {
            var (startDate, endDate) = DateTimeUtil.CalculateWorkTimeRange(workTime);
            query = query.Where(u => 
                (u.PlanStart >= startDate && u.PlanStart <= endDate) ||
                (u.PlanEnd >= startDate && u.PlanEnd <= endDate)
            );
        }

        var planLists = await query.ToListAsync();
        var groupedResults = await ProcessPlanGroups(planLists, planTypes);

        var totalCount = groupedResults.Count;
        var finishedCount = groupedResults.Count(x => x.IsAllFinished);
        var unfinishedCount = totalCount - finishedCount;

        return new
        {
            TotalCount = totalCount,
            FinishedCount = finishedCount,
            UnfinishedCount = unfinishedCount,
            CompletionRate = totalCount > 0 ? Math.Round((double)finishedCount / totalCount * 100, 2) : 0
        };
    }


    #region 已竣工分段对应的未完成分段

    /// <summary>
    /// 获取未完成项统计信息 📊
    /// </summary>
    /// <param name="workTime">工作月份（格式：yyyy-MM）</param>
    /// <returns>统计信息</returns>
    [DisplayName("获取未完成项统计信息")]
    [ApiDescriptionSettings(Name = "GetIncompleteItemsStatistics"), HttpGet]
    public async Task<object> GetIncompleteItemsStatistics([FromBody] string workTime = null)
    {
        // 获取所有计划分类
        var planTypes = await _planTypeRep.AsQueryable()
            .OrderBy(x => x.OrderNo)
            .ToListAsync();
        if (planTypes == null || !planTypes.Any()) throw Oops.Oh("获取计划分类失败");

        // 构建查询条件
        var query = _planListRep.AsQueryable();

        // 如果指定了月份，添加时间范围筛选
        if (!string.IsNullOrWhiteSpace(workTime))
        {
            var (startDate, endDate) = DateTimeUtil.CalculateWorkTimeRange(workTime);
            query = query.Where(u =>
                (u.PlanStart >= startDate && u.PlanStart <= endDate) ||
                (u.PlanEnd >= startDate && u.PlanEnd <= endDate)
            );
        }

        // 获取所有计划数据
        var allPlanLists = await query.ClearFilter<IOrgIdFilter>().ToListAsync();

        // 按船号和分段号分组
        var grouped = allPlanLists.GroupBy(x => new { x.Ch, x.Fd }).ToList();

        int totalSegments = grouped.Count; // 总分段数
        int finishedSegments = 0; // 已完成分段数（分段报验有完工时间）
        int problematicSegments = 0; // 有问题的分段数（分段报验完工但其他工序缺时间）
        int totalIncompleteItems = 0; // 总未完成项数

        var problematicSegmentsList = new List<object>(); // 问题分段详情

        foreach (var group in grouped)
        {
            // 检查该组是否有"分段报验"完成
            var inspectionPlan = group.FirstOrDefault(x => 
                planTypes.Any(pt => pt.Id == x.ClassName && pt.Name == "分段报验"));
            
            // 如果分段报验有实际完工时间，则该分段已完成
            if (inspectionPlan?.ActualEnd.HasValue == true)
            {
                finishedSegments++;
                
                // 检查其他类型的计划是否缺少实际时间
                var incompleteItemsInSegment = new List<object>();
                
                foreach (var plan in group)
                {
                    var planType = planTypes.FirstOrDefault(pt => pt.Id == plan.ClassName);
                    if (planType?.Name == "分段报验") continue; // 跳过分段报验本身

                    var missingStart = !plan.ActualStart.HasValue;
                    var missingEnd = !plan.ActualEnd.HasValue;

                    // 如果缺少实际开工或完工时间，则加入未完成项清单
                    if (missingStart || missingEnd)
                    {
                        totalIncompleteItems++;
                        incompleteItemsInSegment.Add(new
                        {
                            ClassName = planType?.Name,
                            MissingStart = missingStart,
                            MissingEnd = missingEnd,
                            Team = plan.Team
                        });
                    }
                }

                // 如果该分段有未完成项，记录为问题分段
                if (incompleteItemsInSegment.Any())
                {
                    problematicSegments++;
                    problematicSegmentsList.Add(new
                    {
                        Ch = group.Key.Ch,
                        Fd = group.Key.Fd,
                        FinishDate = inspectionPlan.ActualEnd,
                        IncompleteCount = incompleteItemsInSegment.Count,
                        IncompleteItems = incompleteItemsInSegment
                    });
                }
            }
        }

        return new
        {
            TotalSegments = totalSegments,
            FinishedSegments = finishedSegments,
            ProblematicSegments = problematicSegments,
            TotalIncompleteItems = totalIncompleteItems,
            ProblematicRate = finishedSegments > 0 ? Math.Round((double)problematicSegments / finishedSegments * 100, 2) : 0,
            ProblematicSegmentsList = problematicSegmentsList.Take(10).ToList() // 只返回前10个问题分段作为预览
        };
    }
    
    /// <summary>
    /// 获取已完成分段的未完成项清单 🔖
    /// </summary>
    /// <param name="input">查询参数</param>
    /// <returns>未完成项分页列表</returns>
    [DisplayName("获取已完成分段的未完成项清单")]
    [ApiDescriptionSettings(Name = "GetFinishedSegmentIncompleteItems"), HttpPost]
    public async Task<SqlSugarPagedList<IncompleteItemOutput>> GetFinishedSegmentIncompleteItems(IncompleteItemInput input)
    {
        input.Keyword = input.Keyword?.Trim();
        input.Ch = input.Ch?.Trim();
        input.Fd = input.Fd?.Trim();
        input.WorkTime = input.WorkTime?.Trim();

        // 获取所有计划分类
        var planTypes = await _planTypeRep.AsQueryable()
            .OrderBy(x => x.OrderNo)
            .ToListAsync();
        if (planTypes == null || !planTypes.Any()) throw Oops.Oh("获取计划分类失败");

        // 构建查询条件
        var query = _planListRep.AsQueryable();

        // 应用筛选条件
        query = query
            .WhereIF(!string.IsNullOrWhiteSpace(input.Keyword), u => u.Ch.Contains(input.Keyword) || u.Fd.Contains(input.Keyword))
            .WhereIF(!string.IsNullOrWhiteSpace(input.Ch), u => u.Ch.Contains(input.Ch))
            .WhereIF(!string.IsNullOrWhiteSpace(input.Fd), u => u.Fd.Contains(input.Fd));

        // 如果指定了月份，添加时间范围筛选
        if (!string.IsNullOrWhiteSpace(input.WorkTime))
        {
            var (startDate, endDate) = DateTimeUtil.CalculateWorkTimeRange(input.WorkTime);
            query = query.Where(u =>
                (u.PlanStart >= startDate && u.PlanStart <= endDate) ||
                (u.PlanEnd >= startDate && u.PlanEnd <= endDate)
            );
        }

        // 获取所有计划数据
        var allPlanLists = await query.ClearFilter<IOrgIdFilter>().ToListAsync();

        // 按船号和分段号分组
        var grouped = allPlanLists.GroupBy(x => new { x.Ch, x.Fd }).ToList();

        var incompleteItems = new List<IncompleteItemOutput>();

        foreach (var group in grouped)
        {
            // 检查该组是否有"分段报验"完成
            var inspectionPlan = group.FirstOrDefault(x => 
                planTypes.Any(pt => pt.Id == x.ClassName && pt.Name == "分段报验"));
            
            // 如果分段报验有实际完工时间，则该分段已完成
            if (inspectionPlan?.ActualEnd.HasValue == true)
            {
                var finishDate = inspectionPlan.ActualEnd.Value;

                // 检查其他类型的计划是否缺少实际时间
                foreach (var plan in group)
                {
                    var planType = planTypes.FirstOrDefault(pt => pt.Id == plan.ClassName);
                    if (planType?.Name == "分段报验") continue; // 跳过分段报验本身

                    var missingStart = !plan.ActualStart.HasValue;
                    var missingEnd = !plan.ActualEnd.HasValue;

                    // 如果缺少实际开工或完工时间，则加入未完成项清单
                    if (missingStart || missingEnd)
                    {
                        incompleteItems.Add(new IncompleteItemOutput
                        {
                            Id = plan.Id,
                            Ch = plan.Ch,
                            Fd = plan.Fd,
                            ClassName = plan.ClassName,
                            ClassNameFkDisplayName = planType?.Name,
                            WorkAreaId = plan.WorkAreaId,
                            Team = plan.Team,
                            PlanStart = plan.PlanStart,
                            PlanEnd = plan.PlanEnd,
                            ActualStart = plan.ActualStart,
                            ActualEnd = plan.ActualEnd,
                            FinishDate = finishDate,
                            MissingActualStart = missingStart,
                            MissingActualEnd = missingEnd,
                            Remark = plan.Remark
                        });
                    }
                }
            }
        }

        // 按船号、分段、分类排序
        incompleteItems = incompleteItems
            .OrderBy(x => x.Ch)
            .ThenBy(x => x.Fd)
            .ThenBy(x => x.ClassNameFkDisplayName)
            .ToList();

        // 手动分页
        var totalCount = incompleteItems.Count;
        var items = incompleteItems
            .Skip((input.Page - 1) * input.PageSize)
            .Take(input.PageSize)
            .ToList();

        return new SqlSugarPagedList<IncompleteItemOutput>
        {
            Items = items,
            Total = totalCount,
            Page = input.Page,
            PageSize = input.PageSize
        };
    }

    /// <summary>
    /// 批量更新未完成项的实际时间 ✏️
    /// </summary>
    /// <param name="items">批量更新项列表</param>
    /// <returns>更新结果</returns>
    [DisplayName("批量更新未完成项的实际时间")]
    [ApiDescriptionSettings(Name = "BatchUpdateIncompleteItems"), HttpPost]
    public async Task<object> BatchUpdateIncompleteItems(List<BatchUpdateItemInput> items)
    {
        if (items == null || !items.Any())
            throw Oops.Oh("更新项列表不能为空");

        var successCount = 0;
        var failedCount = 0;
        var errors = new List<string>();

        // 使用事务处理批量更新
        await _sqlSugarClient.Ado.BeginTranAsync();
        try
        {
            foreach (var item in items)
            {
                try
                {
                    // 查找对应的计划记录
                    var plan = await _planListRep.GetByIdAsync(item.Id);
                    if (plan == null)
                    {
                        errors.Add($"计划ID {item.Id} 不存在");
                        failedCount++;
                        continue;
                    }

                    // 更新实际时间
                    var hasChanges = false;
                    if (item.ActualStart.HasValue && item.ActualStart != plan.ActualStart)
                    {
                        plan.ActualStart = item.ActualStart;
                        hasChanges = true;
                    }
                    if (item.ActualEnd.HasValue && item.ActualEnd != plan.ActualEnd)
                    {
                        plan.ActualEnd = item.ActualEnd;
                        hasChanges = true;
                    }
                    if (!string.IsNullOrWhiteSpace(item.Remark) && item.Remark != plan.Remark)
                    {
                        plan.Remark = item.Remark;
                        hasChanges = true;
                    }

                    if (hasChanges)
                    {
                        await _planListRep.UpdateAsync(plan);
                        successCount++;
                    }
                    else
                    {
                        successCount++; // 即使没有变更也算成功
                    }
                }
                catch (Exception ex)
                {
                    errors.Add($"更新计划ID {item.Id} 失败: {ex.Message}");
                    failedCount++;
                }
            }

            await _sqlSugarClient.Ado.CommitTranAsync();
        }
        catch (Exception ex)
        {
            await _sqlSugarClient.Ado.RollbackTranAsync();
            throw Oops.Oh($"批量更新失败: {ex.Message}");
        }

        return new
        {
            TotalCount = items.Count,
            SuccessCount = successCount,
            FailedCount = failedCount,
            Errors = errors
        };
    }

    #endregion
}
